// The following ifdef block is the standard way of creating macros which make exporting 
// from a DLL simpler. All files within this DLL are compiled with the CAMERAGL_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see 
// CAMERAGL_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef CAMERAGL_EXPORTS
#define CAMERAGL_API __declspec(dllexport)
#else
#define CAMERAGL_API __declspec(dllimport)
#endif

// This class is exported from the CameraGL.dll
class CAMERAGL_API CCameraGL {
public:
	CCameraGL(void);
	// TODO: add your methods here.
};

extern CAMERAGL_API int nCameraGL;

CAMERAGL_API int fnCameraGL(void);

#pragma once

#include <gl\glew.h>
#include <gl\freeglut.h>
#include "..\Geometry\Geometry.h"

#include <iostream>


class CAMERAGL_API CameraGL
{
	VectorMath::Vector3 currentPos,
		currentEulerRotation_degs,
		fwdVector,
		upVector,
		rightVector;
	double speed;
public:
	CameraGL()
	{
		this->currentPos = VectorMath::Vector3();
		this->currentEulerRotation_degs = VectorMath::Vector3();
		this->fwdVector = VectorMath::Vector3(0, 0, -1);
		this->upVector = VectorMath::Vector3(0, 1, 0);
		this->rightVector = VectorMath::Vector3(1, 0, 0);
		this->speed = 1;
	}

	void SetPosition (VectorMath::Vector3 newPosition)
	{
		this->currentPos = newPosition;
	}

	void SetRotation (VectorMath::Vector3 newEulerRotation_degs)
	{
		this->currentEulerRotation_degs = newEulerRotation_degs;
		if(this->currentEulerRotation_degs.GetX() > 90)
		{
			this->currentEulerRotation_degs.SetX(90);
		}
		else if(this->currentEulerRotation_degs.GetX() < -90)
		{
			this->currentEulerRotation_degs.SetX (-90);
		}
		VectorMath::Vector3 fVect (0, 0, -1),
			uVect (0, 1, 0),
			rVect (1, 0, 0);

		fVect.RotateAroundXAxis (this->currentEulerRotation_degs.GetX());
		fVect.RotateAroundYAxis (this->currentEulerRotation_degs.GetY());
		fVect.RotateAroundZAxis (this->currentEulerRotation_degs.GetZ());

		uVect.RotateAroundXAxis (this->currentEulerRotation_degs.GetX());
		uVect.RotateAroundYAxis (this->currentEulerRotation_degs.GetY());
		uVect.RotateAroundZAxis (this->currentEulerRotation_degs.GetZ());

		rVect.RotateAroundXAxis (this->currentEulerRotation_degs.GetX());
		rVect.RotateAroundYAxis (this->currentEulerRotation_degs.GetY());
		rVect.RotateAroundZAxis (this->currentEulerRotation_degs.GetZ());

		fVect.Normalize();
		uVect.Normalize();
		rVect.Normalize();

		this->fwdVector = fVect;
		this->upVector = uVect;
		this->rightVector = rVect;
	}

	void ApplyLook()
	{
		glRotatef (-this->currentEulerRotation_degs.GetX(), 1.0, 0.0, 0.0);
		glRotatef (-this->currentEulerRotation_degs.GetY(), 0.0, 1.0, 0.0);
		glRotatef (-this->currentEulerRotation_degs.GetZ(), 0.0, 0.0, 1.0);

		glTranslatef (-this->currentPos.GetX(), -this->currentPos.GetY(), -this->currentPos.GetZ());
	}

	void MoveForward (double units)
	{
		this->currentPos = this->currentPos + (this->fwdVector*units);
	}

	void MoveRight (double units)
	{
		this->currentPos = this->currentPos + (this->rightVector*units);
	}

	void MoveUp (double units)
	{
		this->currentPos = this->currentPos + (this->upVector*units);
	}

	void LookRight (double absDegrees)
	{
		VectorMath::Vector3 newRotation = this->currentEulerRotation_degs;
		newRotation.SetY ( newRotation.GetY() - absDegrees );
		this->SetRotation ( newRotation );
	}

	void LookLeft (double absDegrees)
	{
		VectorMath::Vector3 newRotation = this->currentEulerRotation_degs;
		newRotation.SetY ( newRotation.GetY() + absDegrees );
		this->SetRotation ( newRotation );
	}

	void LookUp (double absDegrees)
	{
		VectorMath::Vector3 newRotation = this->currentEulerRotation_degs;
		newRotation.SetX ( newRotation.GetX() + fabs(absDegrees) );

		this->SetRotation ( newRotation );
	}

	void LookDown (double absDegrees)
	{
		VectorMath::Vector3 newRotation = this->currentEulerRotation_degs;
		newRotation.SetX ( newRotation.GetX() - fabs(absDegrees) );
		this->SetRotation ( newRotation );
	}
};